import tkinter as tk
from tkinter import filedialog, scrolledtext, messagebox, ttk
import re
import os

class LatexPunctuationCheckerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("LaTeX标点符号检查工具")
        self.root.geometry("900x700")
        
        # 设置样式
        self.style = ttk.Style()
        self.style.configure("TButton", font=("Arial", 10))
        self.style.configure("TLabel", font=("Arial", 11))
        
        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 文件选择区域
        self.file_frame = ttk.LabelFrame(self.main_frame, text="文件选择", padding="10")
        self.file_frame.pack(fill=tk.X, pady=(0, 10))
        
        self.input_file_label = ttk.Label(self.file_frame, text="输入文件:")
        self.input_file_label.grid(row=0, column=0, sticky=tk.W, padx=(0, 5))
        
        self.input_file_path = tk.StringVar()
        self.input_file_entry = ttk.Entry(self.file_frame, width=50, textvariable=self.input_file_path)
        self.input_file_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
        
        self.browse_button = ttk.Button(self.file_frame, text="浏览...", command=self.browse_file)
        self.browse_button.grid(row=0, column=2, padx=5, pady=5)
        
        self.output_file_label = ttk.Label(self.file_frame, text="输出文件:")
        self.output_file_label.grid(row=1, column=0, sticky=tk.W, padx=(0, 5))
        
        self.output_file_path = tk.StringVar()
        self.output_file_entry = ttk.Entry(self.file_frame, width=50, textvariable=self.output_file_path)
        self.output_file_entry.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
        
        self.output_browse_button = ttk.Button(self.file_frame, text="浏览...", command=self.browse_output_file)
        self.output_browse_button.grid(row=1, column=2, padx=5, pady=5)
        
        # 文本编辑区域
        self.text_frame = ttk.Frame(self.main_frame)
        self.text_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        
        # 左侧文本区域 - 原始文本
        self.left_frame = ttk.LabelFrame(self.text_frame, text="原始LaTeX文本", padding="5")
        self.left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
        
        self.original_text = scrolledtext.ScrolledText(self.left_frame, wrap=tk.WORD, width=40, height=20)
        self.original_text.pack(fill=tk.BOTH, expand=True)
        
        # 右侧文本区域 - 修正后的文本
        self.right_frame = ttk.LabelFrame(self.text_frame, text="修正后的LaTeX文本", padding="5")
        self.right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
        
        self.corrected_text = scrolledtext.ScrolledText(self.right_frame, wrap=tk.WORD, width=40, height=20)
        self.corrected_text.pack(fill=tk.BOTH, expand=True)
        
        # 按钮区域
        self.button_frame = ttk.Frame(self.main_frame)
        self.button_frame.pack(fill=tk.X, pady=10)
        
        self.check_button = ttk.Button(self.button_frame, text="检查标点符号", command=self.check_punctuation)
        self.check_button.pack(side=tk.LEFT, padx=5)
        
        self.save_button = ttk.Button(self.button_frame, text="保存修正结果", command=self.save_corrected_text)
        self.save_button.pack(side=tk.LEFT, padx=5)
        
        self.clear_button = ttk.Button(self.button_frame, text="清空", command=self.clear_all)
        self.clear_button.pack(side=tk.LEFT, padx=5)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(self.main_frame, orient=tk.HORIZONTAL, 
                                          length=100, mode='determinate', 
                                          variable=self.progress_var)
        self.progress_bar.pack(fill=tk.X, pady=(10, 0))
        
        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("准备就绪")
        self.status_bar = ttk.Label(self.main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(fill=tk.X, pady=(5, 0))

    def browse_file(self):
        """打开文件浏览对话框选择输入文件"""
        file_path = filedialog.askopenfilename(
            title="选择LaTeX文件",
            filetypes=[("TeX files", "*.tex"), ("All files", "*.*")]
        )
        if file_path:
            self.input_file_path.set(file_path)
            # 设置默认输出文件名
            input_dir = os.path.dirname(file_path)
            input_filename = os.path.basename(file_path)
            name, ext = os.path.splitext(input_filename)
            output_filename = f"{name}_corrected{ext}"
            output_path = os.path.join(input_dir, output_filename)
            self.output_file_path.set(output_path)
            
            # 加载文件内容
            self.load_file_content()

    def browse_output_file(self):
        """打开文件浏览对话框选择输出文件"""
        file_path = filedialog.asksaveasfilename(
            title="保存为",
            filetypes=[("TeX files", "*.tex"), ("All files", "*.*")],
            defaultextension=".tex",
            initialfile=self.output_file_path.get()
        )
        if file_path:
            self.output_file_path.set(file_path)

    def load_file_content(self):
        """加载选择的文件内容到原始文本框"""
        file_path = self.input_file_path.get()
        if file_path and os.path.exists(file_path):
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                
                # 清空并设置原始文本
                self.original_text.delete(1.0, tk.END)
                self.original_text.insert(tk.END, content)
                self.status_var.set(f"已加载文件: {os.path.basename(file_path)}")
            except Exception as e:
                messagebox.showerror("错误", f"无法读取文件: {str(e)}")
                self.status_var.set("文件加载失败")
        else:
            messagebox.showwarning("警告", "请选择有效的文件")

    def check_punctuation(self):
        """检查并修正标点符号"""
        # 获取原始文本
        original_content = self.original_text.get(1.0, tk.END)
        
        if not original_content.strip():
            messagebox.showinfo("提示", "请先加载或输入LaTeX文本")
            return
        
        try:
            # 设置进度条开始
            self.progress_var.set(10)
            self.root.update_idletasks()
            
            self.status_var.set("正在处理标点符号...")
            # 执行标点符号检查
            corrected_content = self.process_punctuation(original_content)
            
            self.progress_var.set(90)
            self.root.update_idletasks()
            
            # 显示修正后的文本
            self.corrected_text.delete(1.0, tk.END)
            self.corrected_text.insert(tk.END, corrected_content)
            
            # 高亮显示修改的部分
            self.highlight_differences()
            
            self.progress_var.set(100)
            self.status_var.set("标点符号检查完成")
            
            # 修改计数
            original_chars = set([c for c in original_content if c in ',.:;?!()[]'])
            corrected_chars = set([c for c in corrected_content if c in '，。：；？！（）【】'])
            modified_count = sum(1 for c1, c2 in zip(original_content, corrected_content) if c1 != c2)
            
            messagebox.showinfo("处理完成", f"共修正了 {modified_count} 处标点符号")
            
        except Exception as e:
            self.progress_var.set(0)
            self.status_var.set("处理过程中发生错误")
            messagebox.showerror("错误", f"处理过程中发生错误: {str(e)}")

    def process_punctuation(self, text):
        """检查并修正LaTeX文本中的中英文标点符号"""
        # 定义LaTeX命令和环境的正则表达式
        latex_command_pattern = r'\\[a-zA-Z]+((\*)?(\[[^\]]*\])?(\{[^}]*\})*)?'
        latex_environment_begin = r'\\begin\{[^}]*\}'
        latex_environment_end = r'\\end\{[^}]*\}'
        latex_math_pattern = r'\$[^$]*\$'
        latex_patterns = [latex_command_pattern, latex_environment_begin, latex_environment_end, latex_math_pattern]
        
        # 定义需要修正的标点符号对应关系
        punctuation_map = {
            # 中文环境中的英文标点改为中文标点
            ',': '，',
            '.': '。',
            ':': '：',
            ';': '；',
            '?': '？',
            '!': '！',
            '(': '（',
            ')': '）',
            '[': '【',
            ']': '】',
        }
        
        # 中文字符范围
        chinese_char_pattern = r'[\u4e00-\u9fff]'
        
        # 将文本按行分割
        lines = text.split('\n')
        result = []
        
        # 更新进度条
        total_lines = len(lines)
        processed_lines = 0
        
        # 处理每一行
        for line in lines:
            # 更新进度条
            processed_lines += 1
            if processed_lines % 10 == 0:  # 每10行更新一次进度
                progress = 10 + (80 * processed_lines / total_lines)  # 10%-90%的进度范围
                self.progress_var.set(progress)
                self.root.update_idletasks()
            
            # 跳过纯LaTeX命令行
            if line.strip().startswith('\\') and not re.search(chinese_char_pattern, line):
                result.append(line)
                continue
            
            # 找出所有的LaTeX标记并保存位置
            latex_pieces = []
            for pattern in latex_patterns:
                for match in re.finditer(pattern, line):
                    latex_pieces.append((match.start(), match.end(), match.group()))
            
            # 按位置排序
            latex_pieces.sort()
            
            # 处理文本，保留LaTeX部分不变
            last_end = 0
            processed_line = ""
            
            for start, end, latex_part in latex_pieces:
                # 处理LaTeX标记之前的文本
                text_before = line[last_end:start]
                processed_text_before = self.process_text(text_before, punctuation_map)
                processed_line += processed_text_before
                
                # 添加保持不变的LaTeX标记
                processed_line += latex_part
                last_end = end
            
            # 处理最后一个LaTeX标记之后的文本
            if last_end < len(line):
                text_after = line[last_end:]
                processed_text_after = self.process_text(text_after, punctuation_map)
                processed_line += processed_text_after
            
            # 如果没有任何LaTeX标记，直接处理整行
            if not latex_pieces:
                processed_line = self.process_text(line, punctuation_map)
            
            result.append(processed_line)
        
        return '\n'.join(result)
    
    def process_text(self, text, punctuation_map):
        """处理普通文本段落中的标点符号"""
        if not text:
            return text
        
        # 检查是否有中文字符
        has_chinese = bool(re.search(r'[\u4e00-\u9fff]', text))
        
        # 如果没有中文，不处理
        if not has_chinese:
            return text
        
        # 处理中英文字符混合的文本
        result = ""
        i = 0
        while i < len(text):
            char = text[i]
            
            # 检查前后字符上下文
            prev_char = text[i-1] if i > 0 else ""
            next_char = text[i+1] if i < len(text)-1 else ""
            
            # 如果是标点符号且前后有中文，替换为中文标点
            if char in punctuation_map and (
                re.match(r'[\u4e00-\u9fff]', prev_char) or 
                re.match(r'[\u4e00-\u9fff]', next_char)
            ):
                result += punctuation_map[char]
            else:
                result += char
            
            i += 1
        
        return result

    def highlight_differences(self):
        """高亮显示原始文本和修正文本之间的差异"""
        original = self.original_text.get(1.0, tk.END)
        corrected = self.corrected_text.get(1.0, tk.END)
        
        # 为修正后的文本框配置标签
        self.corrected_text.tag_configure("diff", background="#FFFF99")
        
        # 逐字符比较
        line_num = 1
        char_num = 0
        
        for i, (orig_char, corr_char) in enumerate(zip(original, corrected)):
            if orig_char != corr_char:
                # 计算行号和字符位置
                line_count = corrected[:i].count('\n') + 1
                if line_count > line_num:
                    line_num = line_count
                    char_num = 0
                
                char_num = i - corrected.rfind('\n', 0, i) - 1 if corrected.rfind('\n', 0, i) >= 0 else i
                
                # 高亮差异
                start_pos = f"{line_num}.{char_num}"
                end_pos = f"{line_num}.{char_num + 1}"
                self.corrected_text.tag_add("diff", start_pos, end_pos)

    def save_corrected_text(self):
        """保存修正后的文本到指定文件"""
        output_path = self.output_file_path.get()
        
        if not output_path:
            output_path = filedialog.asksaveasfilename(
                title="保存修正后的文件",
                filetypes=[("TeX files", "*.tex"), ("All files", "*.*")],
                defaultextension=".tex"
            )
            if not output_path:
                return
            self.output_file_path.set(output_path)
        
        corrected_content = self.corrected_text.get(1.0, tk.END)
        
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(corrected_content)
            
            self.status_var.set(f"已保存到: {os.path.basename(output_path)}")
            messagebox.showinfo("成功", f"修正后的文本已保存到:\n{output_path}")
        except Exception as e:
            messagebox.showerror("错误", f"保存文件时出错: {str(e)}")
            self.status_var.set("保存失败")

    def clear_all(self):
        """清空所有文本区域"""
        self.original_text.delete(1.0, tk.END)
        self.corrected_text.delete(1.0, tk.END)
        self.progress_var.set(0)
        self.status_var.set("准备就绪")

def main():
    root = tk.Tk()
    app = LatexPunctuationCheckerGUI(root)
    root.mainloop()

if __name__ == "__main__":
    main()
